package com.fengye.security.rest;

import com.fengye.security.config.AppProperties;
import com.fengye.security.domain.User;
import com.fengye.security.domain.dto.TokenDto;
import com.fengye.security.domain.dto.UserDto;
import com.fengye.security.domain.vo.TokenVo;
import com.fengye.security.exception.DuplicateProblem;
import com.fengye.security.security.filter.JwtAuthenticationToken;
import com.fengye.security.security.service.UserDetailsServiceImpl;
import com.fengye.security.utils.JwtUtil;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.MessageSource;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Locale;

/**
 * @author fengyexjtu@126.com
 * @date 2022年04月13日 11:04 AM
 */

@RestController
@RequestMapping("/authorize")
@RequiredArgsConstructor
//@AllArgsConstructor
//@NoArgsConstructor
@Slf4j
public class AuthorizeResource {

    private final List<UserDetailsService> userDetailsServiceList;
    private final PasswordEncoder passwordEncoder;

    private final AppProperties appProperties;

    private final JwtUtil jwtUtil;


    private final UserDetailsServiceImpl userService;
    private final MessageSource messageSource;

    @PostMapping("/register")
    public void register(@Valid @RequestBody UserDto userDto, Locale locale) {
        if (userService.isUsernameExisted(userDto.getUsername())) {
            throw new DuplicateProblem(messageSource.getMessage(
                    "Exception.duplicate.title", null, locale),
                    messageSource.getMessage("Exception.duplicate.username", null, locale));
        }
        if (userService.isEmailExisted(userDto.getEmail())) {
            throw new DuplicateProblem(messageSource.getMessage(
                    "Exception.duplicate.title", null, locale),
                    messageSource.getMessage("Exception.duplicate.email", null, locale));
        }
        if (userService.isMobileExisted(userDto.getMobile())) {
            throw new DuplicateProblem(messageSource.getMessage(
                    "Exception.duplicate.title", null, locale),
                    messageSource.getMessage("Exception.duplicate.mobile", null, locale));
        }
        val user = User.builder()
                .username(userDto.getUsername())
                .name(userDto.getName())
                .email(userDto.getEmail())
                .mobile(userDto.getMobile())
                .password(userDto.getPassword())
                .enabled(false)
                .build();
        userService.register(user);
    }

    @PostMapping("/token")
    public TokenVo getTokenVo(@Valid @RequestBody TokenDto tokenDto) {

        String username = tokenDto.getUsername();
        for (UserDetailsService userDetailsService : userDetailsServiceList) {
            try {
                UserDetails user = userDetailsService.loadUserByUsername(username);
                if (user == null) {
                    continue;
                }

                String hashedPassword = user.getPassword();
                if (hashedPassword.equals(tokenDto.getPassword())) {
                    return createTokenVo(user);
                } else if (passwordEncoder.matches(tokenDto.getPassword(), hashedPassword)) {
                    return createTokenVo(user);
                }


            } catch (UsernameNotFoundException e) {
                log.debug("当前 userDetailsService 并未找到用户，继续");
            }
        }

        throw new BadCredentialsException("用户名或密码错误");
    }

    private TokenVo createTokenVo (UserDetails user) {
        TokenVo tokenVo = new TokenVo();
        tokenVo.setAccessToken(jwtUtil.createAccessToken(user));
        tokenVo.setRefreshToken(jwtUtil.createRefreshToken(user));
        return tokenVo;
    }

    @PostMapping("/refresh/token")
    public TokenVo refreshToken(@RequestParam String refreshToken, @RequestHeader("Authorization") String token){
        String accessToken = token.replace(appProperties.getJwt().getPrefix(), "");
        log.info("accessToken = {}", accessToken);
        log.info("refreshToken = {}", refreshToken);
        if (jwtUtil.validAccessToken(accessToken)){
            throw new AccessDeniedException("accessToken错误");
        }
        TokenVo tokenVo = new TokenVo();
        if (jwtUtil.validRefreshToken(refreshToken)){
            tokenVo.setAccessToken(jwtUtil.createAccessTokenByRefreshToken(refreshToken));
            tokenVo.setRefreshToken(refreshToken);
            return tokenVo;
        }
        throw new BadCredentialsException("refreshToken 错误");


    }
}
